/*
 * GeoVISTA Center (Penn State, Dept. of Geography)
 * Copyright (c), 2003-2011,  Jin Chen and Alan M. MacEachren, GeoVISTA Center, Penn State University
 * Licensed under Simplified BSD License
 *
 * It should be an inner class of  AxisLocationCfg, but since it is too complicate and big, we move it as an seperated class
 * @author: jin Chen 
 * @date: Nov 22, 2004$
 * @version: 1.0
 */
package edu.psu.geovista.app.pcp.plot.control.gui;


import edu.psu.geovista.app.dataloader.v1.gui.DataSelectPane;
import edu.psu.geovista.app.pcp.plot.control.AxisLocationCfg;
import edu.psu.geovista.app.pcp.plot.control.tools.AxisPlaceTool;
import edu.psu.geovista.app.pcp.toolkits.Math.JMath;
import edu.psu.geovista.app.pcp.toolkits.selectcontrol.SelectItemsPane;
import edu.psu.geovista.app.pcp.toolkits.selectcontrol.ui.VerticalBttnsPane;
import edu.psu.geovista.app.pcp.toolkits.table.ConfigureTableModel;
import edu.psu.geovista.app.plot.axis.AxisList;
import edu.psu.geovista.app.plot.axis.YAxis;

import javax.swing.*;
import javax.swing.event.TableModelEvent;
import javax.swing.event.TableModelListener;
import javax.swing.table.TableColumn;
import java.awt.*;
import java.util.*;

public abstract class AxisPlaceControl extends SelectItemsPane{
        private int plotMode;
        private boolean repaintPlot=true;


        AxisLocationCfg axisLocConfig;
        private AxisPlaceTool axisPlCmd;
        private AxisList yaxisList;
        HashSet dataNameList;
         protected Map columndescription;

    public AxisPlaceControl(AxisLocationCfg axisLocConfig) {
        this.axisLocConfig=axisLocConfig;
        this.setAxisPlCmd(axisLocConfig.getAxisPlCmd());
        this.setYaxisList(axisLocConfig.getYaxisList());
        this.dataNameList = axisLocConfig.getDataNameList() ;
        this.columndescription = axisLocConfig.getColumndescription();
        this.initLeftTable() ;
        this.initRightTable() ;
        this.setLeftSectionName("Hidden");
        this.setRightSectionName("Visible");

    }
    /*******************************************************************************************************
     *                service
     *******************************************************************************************************/
    public void selectInRightTable(String varname){
        this.rightTable.setSelectedRowWithID(varname);
    }

    public String  getSelectedInRightTable(){
        int index = rightTable.getSelectedRow();
        if(index>=0)
            return (String) rightTable.getRowID(index);
        else
            return "";
    }

      /*  public AxisPlaceControl() {
            this.initLeftTable() ;
            this.initRightTable() ;
            this.setLeftSectionName("Hidden");
            this.setRightSectionName("Visible");

        }*/
        protected void layoutTables() {
        layoutTable(TABLE_LEFT,new Dimension(250, 349),new Point(0,0),new Point(3,1));
        layoutTable(TABLE_RIGHT,new Dimension(200, 349),new Point(3,0),new Point(2,1));
    }

        protected void initButtons() {

            //this.setButtonPane(new SingleButtonsPane());
             VerticalBttnsPane selectP = createSelectBttnsPane();
        VerticalBttnsPane updnP = createUpDownBttnsPane();

        btnP.setLayout(new BorderLayout());
        btnP.add(selectP);

        /*JPanel p=new JPanel();
        p.setLayout(new BorderLayout());
        p.add(updnP) ;*/
        this.RTableP.add(updnP, BorderLayout.EAST );

        }
        protected void initLeftTable() {


             //1. get names and their descriptions
        Object[] attrs =  dataNameList.toArray();
        Arrays.sort(attrs);//sort the names
        Map descs = this.columndescription;
        //String[] descs=new String[attrs.length ];

        //2. convert the data into a vector that contain vectors, each of which contain a name and a description
        Vector data=new Vector();
        for (int i=0;i<attrs.length ;i++){
             String desc="";
            String name = (String) attrs[i];
            Object o=descs.get(name);
             if(o!=null)
                desc=(String) o;
             Vector record=new Vector();
             record.add(name); record.add(desc);
             data.add(record);

        }
        //String [] colNames=new String[]{DataListPane.Col_Name,DataListPane.Col_Desc };
        //3. define column name
        Vector colNames=new Vector();
        colNames.add(DataSelectPane.Col_Name);
        colNames.add(DataSelectPane.Col_Desc);

        //4. make a table model using the vector
        ConfigureTableModel model=new ConfigureTableModel();
        model.setDataVector(data,colNames);

        setData(model);
        this.leftTable.colorAllItem(true);
        this.leftTable.setColumnsWidth(new int[]{1,3});
        }

        /*****************************************
         *                table
         *****************************************/
        //1.create tableModel //2. init values
        public  void initRightTable() {
            ArrayList yList=getYaxisList().getIndexSortAxisList();
            int numOfAxis=getYaxisList().size() ;
            //1. Model
            Vector colName=new Vector();
            // 
            setPlotMode(getAxisPlCmd().getPlotMode());
            colName.add("Name");colName.add("Axis Visible"); colName.add("Scale");
            Class[] types=null;
            int[] columnWeight=new int[]{5,1,1};// 
            /*if(getPlotMode()==DfPcp.MODE_TIMESERIES ){
                colName.add("DisplayType");
                types  = new Class [] {
                    java.lang.String.class, java.lang.Boolean.class,java.lang.Object.class,java.lang.Object.class
                };
                columnWeight=new int[]{5,1,1,2};//one more column
            }
            else{*/
                types  = new Class [] {
                    java.lang.String.class, java.lang.Boolean.class,java.lang.Object.class
                };
            /*}*/

            boolean[] editable={false,true,true,true};
            ConfigureTableModel model=new ConfigureTableModel(colName,numOfAxis){
                public boolean isCellEditable(int row, int column) {
                    int index =this.getColumnIndex("DisplayType");
                    if (index>=0&&column==index){
                        //For PCP, its initial value is YAxis.DTYPE_Nml, thus won't be able to update
                        //For Time Series, its initial value is NOT YAxis.DTYPE_Nml, thus will be able to update
                        if((this.getValueAt(row,column)).equals(YAxis.DTYPE_Nml ))return false;
                    }
                    return super.isCellEditable(row,column) ;
                }
            };
            model.setTypes(types);
            model.setEditables(editable);
            this.rightTable.setModel(model);
            //2. Set column values
            Iterator iter=yList.iterator() ;
            int row=0;

            while(iter.hasNext()){
                YAxis yaxis = (YAxis)iter.next();
                //table.setValueAt(new Integer(row), row,colName.indexOf("Index") ); //displayIndex
                this.rightTable.setValueAt(yaxis.getName() ,row,colName.indexOf("Name"));

                this.rightTable.setValueAt(new Boolean(yaxis.isVisible()) ,row,colName.indexOf("Axis Visible") );
                this.rightTable.setValueAt(getDisplayValueForLabelScale(yaxis.getLabelScale() ),row,colName.indexOf("Scale") );
                /*if(this.getPlotMode() ==DfPcp.MODE_TIMESERIES ){
                    this.rightTable.setValueAt(yaxis.getDisplayType() ,row,colName.indexOf("DisplayType"));
                }*/
                row++;
            }
            //DisplayType
           /* if (getPlotMode()==DfPcp.MODE_TIMESERIES) {
                TableColumn typeColumn=this.rightTable.getColumn("DisplayType");
                JComboBox comb=new JComboBox();
                String[] displayType=new String[]{YAxis.DTYPE_Qty,YAxis.DTYPE_Ord ,YAxis.DTYPE_Nml };
                for (int i=0;i<displayType.length ;i++){
                    comb.addItem(displayType[i]);

                }
                typeColumn.setCellEditor(new DefaultCellEditor(comb));
            }*/
            //Label scale
            TableColumn scaleColumn=this.rightTable.getColumn("Scale");
            JComboBox scaleComb=new JComboBox();
            String[] scaleType=new String[]{"*1","*K" ,"*M"};
            for (int i=0;i<scaleType.length ;i++){

                scaleComb.addItem(scaleType[i]);
            }

            scaleColumn.setCellEditor(new DefaultCellEditor(scaleComb));

            this.rightTable.getModel().addTableModelListener(new TableModelListener(){
                public void tableChanged(TableModelEvent e) {
                    //System.out.println("table model changed");
                    applyVisibleAxisTableChanged( e);
                }
            } );
            //setColumnSize(columnWeight);
            this.setColumnsWidth(columnWeight,SelectItemsPane.TABLE_RIGHT);
            autoScale();
        }
        /**
         * Automatically set scale so that 1000=1k and 1000,000=1M
         */
        protected  void autoScale() {
            Object[] cnames = rightTable.getColumnValues("Name");
            for (int i=0;i<cnames.length ;i++){
                // 
                this.setRepaintPlot(false);
                if(i==cnames.length-1){//only repaint plot at end
                    this.setRepaintPlot(true);
                }
                String axisname=(String) cnames[i];
                YAxis axis = getYaxisList().getAxis(axisname);
                if(axis!=null){
                float max = axis.getTickRange().getMax();
                String scale=getScaleType(max);
                rightTable.setValueAt(scale,i,"Scale");
                }

            }
        }
        /*private void autoSetScale(String axisname){
            YAxis axis = yaxisList.getAxis(axisname);
            float max = axis.getTickRange().getMax();
            String scale=getScaleType(max);

            //scaleComb.setSelectedItem(scale);
        }*/

        public  void moveRight(){
            super.moveRight();

            autoScale();
        }

        public  void moveAllRight(){
            super.moveAllRight();
            autoScale();
        }

        /**
         * for automatically set scale type based on maximum value of the axis
         * @param
         * @return
         */
        private String getScaleType(float max){

            if(max>=1000&&max<1000000){
                return "*K";
            }
            else if(max>=1000000){
                return "*M";
            }
            else{
                return "*1";
            }
        }
        protected  String getDisplayValueForLabelScale(int scale){
            if(scale==JMath.LABEL_x1 ){
                return "*1";
            }
            else if(scale==JMath.LABEL_xK ){
                return "*K";
            }
            else if(scale==JMath.LABEL_x1 ){
                return "*M";
            }
            return "1";
        }
        public  void selectRecord(Object[] data) {
        String name=(String) data[0];//the ID (name of a attribute) of the record
        this.addRecord(name);
        //To change body of implemented methods use File | Settings | File Templates.
    }
        protected void addRecord(String name) {


           /*Forts
           if (this.getPlotMode() ==DfPcp.MODE_TIMESERIES ) {
                Object[] arow = {name, Boolean.TRUE ,"*1",YAxis.DTYPE_Nml};
                this.rightTable.addRow(arow);
            }
            else{*/
                Object[] arow = {name, Boolean.TRUE ,"*1"};
                this.rightTable.addRow(arow);
/*
            }*/

        }

        protected void actOnButtonClick(String btnName) {
            //"Right","Left","Right all","Left all","Up","Down","Apply"
            if(btnName.equals("Show") ){
                this.moveRight();
            }
            else if(btnName.equals("Hide") ){
                this.moveLeft() ;
            }
            else if(btnName.equals("Up")){
                /* int row=this.rightTable.getSelectedRow() ;
                if (row>0){
                rightTable.moveRowUp(row);
                }*/
                this.moveUp();

            }
            else if(btnName.equals("Down")){
                /*int row=this.rightTable.getSelectedRow() ;
                if (row>=0&&row<rightTable.getRowCount() ){
                rightTable.moveRowDown(row);
                }*/
                this.moveDown() ;
            }
            else if (btnName.equals("Show all")){
                this.moveAllRight() ;
            }
            else if (btnName.equals("Hide all")){
                this.moveAllLeft() ;
            }
            else if (btnName.equals("Top")){
             this.moveTop() ;
             //System.out.println("Top");
        }
         else if (btnName.equals("Bottom")){
             // 
             this.moveBottom() ;
             //System.out.println("Bottom");
        }
            else if (btnName.equals("Apply")){
                //System.out.println("Apply");
                apply();


            }
        }
        /**
         *  
         */
        public   void apply() {
            Object[] obs=this.rightTable.getSortValueAtColumn("Name");
            Object[] Visible=this.rightTable.getSortValueAtColumn("Axis Visible");
            boolean[] visible=new boolean[Visible.length ];
            for (int i=0;i<visible.length ;i++){
                visible[i]=((Boolean)Visible[i]).booleanValue() ;
            }
            String[] names=new String[obs.length ];
            System.arraycopy(obs,0,names,0,obs.length );// 
            getAxisPlCmd().setYAxisAsValid(names, visible);


            //initValue() ;    
        }

        /**
         * Listen to change on visibleAxisTable
         * @param e
         */
        public void applyVisibleAxisTableChanged(TableModelEvent e) {
            int col=e.getColumn() ;
            int displayTypeCol=((ConfigureTableModel)rightTable.getModel()).getColumnIndex("DisplayType");
            int scaleCol= ((ConfigureTableModel)rightTable.getModel()).getColumnIndex("Scale");
            if(displayTypeCol>=0&&col==displayTypeCol&&e.getType()==TableModelEvent.UPDATE ){
               // 
               // 
                //update axis's display type
                int f=e.getFirstRow() ;
                int l=e.getLastRow() ;
                for (int i=f;i<=l;i++){
                    String axisName=(String) this.rightTable.getValueAt(i,"Name");
                    String dType=(String) this.rightTable.getValueAt(i,"DisplayType");
                    YAxis axis=getYaxisList().getAxis(axisName);
                    String curType=axis.getDisplayType() ;
                    if(!curType.equals(dType) ){
                        boolean suc=trySetDisplayType(axis,dType);
                        if(!suc){
                            this.rightTable.setValueAt(curType,i,"DisplayType");
                        }

                    }
                }
            }
            else if(col==scaleCol&&e.getType()==TableModelEvent.UPDATE ){
                //update axis's label scale type
                // 
                // 
                //  
                int f=e.getFirstRow() ;
                int l=e.getLastRow() ;
                for (int i=f;i<=l;i++){// 
                    String axisName=(String) this.rightTable.getValueAt(i,"Name");
                    String sType=(String) this.rightTable.getValueAt(i,"Scale");
                    YAxis axis=getYaxisList().getAxis(axisName);
                    if(sType.equals("*1") ){
                        axis.setLabelScale(JMath.LABEL_x1 );
                    }
                    else if(sType.equals("*K") ){
                        axis.setLabelScale(JMath.LABEL_xK );
                    }
                    else if(sType.equals("*M") ){
                        axis.setLabelScale(JMath.LABEL_xM );
                    }
                    if(this.isRepaintPlot() ){// 
                        getAxisPlCmd().repaintAxisLayer();
                        getAxisPlCmd().repaintPlot() ;
                    }
                }
                //}
            }

        }
        //call
        protected abstract boolean trySetDisplayType(YAxis axis,String type);

        public int getPlotMode() {
            return plotMode;
        }

        public void setPlotMode(int plotMode) {
            this.plotMode = plotMode;
        }

        public boolean isRepaintPlot() {
            return repaintPlot;
        }

        public void setRepaintPlot(boolean repaintPlot) {
            this.repaintPlot = repaintPlot;
        }

    public void setAxisPlCmd(AxisPlaceTool axisPlCmd) {
        this.axisPlCmd = axisPlCmd;
    }

    public void setYaxisList(AxisList yaxisList) {
        this.yaxisList = yaxisList;
    }

    public void setDataNameList(HashSet dataNameList) {
        this.dataNameList = dataNameList;
    }

    public void setColumndescription(Hashtable columndescription) {
        this.columndescription = columndescription;
    }


    public AxisList getYaxisList() {
        return yaxisList;
    }

    public AxisPlaceTool getAxisPlCmd() {
        return axisPlCmd;
    }
} //innner class
